import warnings

import chess

import src.util as util
import src.evaluate as evaluate
import src.global_config as gl


class Chess:

    # 获取一个空棋盘 数组
    @staticmethod
    def get_empty_board_list() -> list:
        return [
            [0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0],
        ]

    # 获取关联的棋子对象
    @staticmethod
    def get_empty_piece_type_list() -> dict:
        return {
            'bishop': [],
            'pawn': [],
            'queen': [],
            'knight': [],
            'rook': [],
            'king': []
        }

    # 根据fen获取当前是谁走
    @staticmethod
    def get_current_color_by_fen(fen: str) -> bool or evaluate.Color:
        fen_list = fen.split(' ')
        color = fen_list[1]
        if color == 'w':
            return True
        else:
            return False

    # 因为一个fen表示当前多少手 以及多少步没吃子的数据意义不大 所以把他们忽略掉 获取开局库的时候有用
    # 吃过路兵也去掉吧。。
    @staticmethod
    def drop_last_fen(fen: str) -> str:
        fen = fen.split(' ')
        res = ''
        for i in range(len(fen) - 3):
            res += fen[i]
            if i != len(fen) - 3 - 1:
                res += ' '
        return res

    # 把一个uci字符串转为棋步 b1c3变为Nc3
    @staticmethod
    def parse_uci_2_step(step, parsed_board: list, board) -> str:
        warnings.warn('废弃', DeprecationWarning)
        step_str = str(step)
        print(parsed_board)
        # 移动前的x,y 移动后的x,y 以及升变
        b_x = util.ALPHABET[step_str[0:1]]
        b_y = util.ALPHABET[step_str[1:2]]
        e_x = step_str[2:3]
        e_y = step_str[3:4]

        promote = step_str[4:5] or None
        if promote is not None:
            promote_text = '=' + promote.upper()
        else:
            promote_text = ''
        x = b_x - 1
        y = 8 - b_y
        dest_x = util.ALPHABET[e_x] - 1
        dest_y = 8 - util.ALPHABET[e_y]

        kill = ''

        pieces: str = parsed_board[y][x]
        if pieces == '.' or pieces.upper() == 'P':
            name = ''
        else:
            name = pieces.upper()
        if parsed_board[dest_y][dest_x] != '.':
            kill = 'x'
        board.push(step)
        # 增加对将军和将杀的校验
        is_check: bool = board.is_check()
        is_checkmate: bool = board.is_checkmate()
        res = str(name) + kill + str(e_x) + str(e_y) + str(promote_text)
        if is_checkmate:
            res = res + '#'
            return res

        if is_check:
            res = res + '+'

        return res

    @staticmethod
    def parse_board(board: chess.Board) -> list:
        line = str(board).split('\n')
        temp_list = []
        for i in range(len(line)):
            single = line[i].split(' ')
            temp_list.append(single)
        return temp_list

    # 获取单纯局面的分数 不考虑其他因素
    @staticmethod
    def get_pieces_value(board: list) -> float:
        warnings.warn('已经不使用这个函数了', DeprecationWarning)
        value = 0
        for i in range(8):
            for j in range(8):
                single = board[i][j]
                value += evaluate.SCORE_LIST[single]
        return value / 100

    # 计算双方各有多少棋子
    @staticmethod
    def count_pieces(board: list) -> dict:
        res = {
            "white": {
                'pawn': 0,
                'knight': 0,
                'bishop': 0,
                'rook': 0,
                'queen': 0,
                'light': 0,
            },
            "black": {
                'pawn': 0,
                'knight': 0,
                'bishop': 0,
                'rook': 0,
                'queen': 0,
                'light': 0
            },
        }
        for i in range(8):
            for j in range(8):
                place = board[i][j]
                if place == evaluate.Pieces.BLACK_PAWN:
                    res['black']['pawn'] += 1
                elif place == evaluate.Pieces.BLACK_ROOK:
                    res['black']['rook'] += 1
                elif place == evaluate.Pieces.BLACK_KNIGHT:
                    res['black']['knight'] += 1
                    res['black']['light'] += 1
                elif place == evaluate.Pieces.BLACK_BISHOP:
                    res['black']['bishop'] += 1
                    res['black']['light'] += 1
                elif place == evaluate.Pieces.BLACK_QUEEN:
                    res['black']['queen'] += 1
                elif place == evaluate.Pieces.WHITE_PAWN:
                    res['white']['pawn'] += 1
                elif place == evaluate.Pieces.WHITE_ROOK:
                    res['white']['rook'] += 1
                elif place == evaluate.Pieces.WHITE_KNIGHT:
                    res['white']['knight'] += 1
                    res['white']['light'] += 1
                elif place == evaluate.Pieces.WHITE_BISHOP:
                    res['white']['bishop'] += 1
                    res['white']['light'] += 1
                elif place == evaluate.Pieces.WHITE_QUEEN:
                    res['white']['queen'] += 1
        return res

    # 获取棋盘上所有的叠兵 小写的p是黑棋 P是白棋
    @staticmethod
    def get_pawn_piled(board: list) -> tuple:
        res = []
        white_res = []
        black_res = []
        for j in range(8):
            temp_black = []
            temp_white = []

            for i in range(8):
                # 列
                column = board[i][j]
                if column == evaluate.Pieces.WHITE_PAWN:
                    temp_white.append({
                        'x': i,
                        'y': j,
                        'piece': column
                    })
                elif column == evaluate.Pieces.BLACK_PAWN:
                    temp_black.append({
                        'x': i,
                        'y': j,
                        'piece': column
                    })
            if len(temp_white) != 0 and len(temp_white) != 1:
                white_res.extend(temp_white)
            if len(temp_black) != 0 and len(temp_black) != 1:
                black_res.extend(temp_black)
        res.extend(white_res)
        res.extend(black_res)
        return res, white_res, black_res

    # 判断目前的对局处于什么样的进程 OG MG EG
    def get_current_game_course(self, board: list) -> str:
        res = self.count_pieces(board)
        # 无后直接残局
        if res['black']['queen'] == 0 or res['white']['queen'] == 0:
            return evaluate.GameCourse.END_GAME
        # 双方兵大于? 轻子也没兑换多少 属于开局
        if (res['black']['pawn'] >= evaluate.GameCourse.OPEN_PAWN_THRESHOLD and res['white'][
            'pawn'] >= evaluate.GameCourse.OPEN_PAWN_THRESHOLD
                and res['black']['light'] >= evaluate.GameCourse.OPEN_PAWN_LIGHT_THRESHOLD and res['white'][
                    'light'] >= evaluate.GameCourse.OPEN_PAWN_LIGHT_THRESHOLD):
            return evaluate.GameCourse.OPEN_GAME
        # 轻子小于等于?车也少了 基本算残局
        if (res['black']['light'] <= evaluate.GameCourse.END_LIGHT_THRESHOLD and res['white'][
            'light'] <= evaluate.GameCourse.END_LIGHT_THRESHOLD
                or (res['black']['rook'] < evaluate.GameCourse.END_ROOK_THRESHOLD) and res['white'][
                    'rook'] < evaluate.GameCourse.END_ROOK_THRESHOLD):
            return evaluate.GameCourse.END_GAME
        # 默认其他都是中局
        return evaluate.GameCourse.MIDDLE_GAME

    # 判断这个棋子是不是白棋
    @staticmethod
    def is_white(piece: str) -> bool:
        if piece.isupper():
            return True
        else:
            return False

    # 获取这个棋子的攻击
    def get_single_attack(self, board: chess.Board, i, j):
        res = board.attacks(square=evaluate.Board.BOARD_PLACE[i][j])
        res = self.parse_board(res)
        return res

    # 判断这个棋子是不是轻子 B N
    @staticmethod
    def is_light(piece: str) -> bool:
        if piece == 'b' or piece == 'n' or piece == 'B' or piece == 'N':
            return True
        else:
            return False

    # 是否是重子
    @staticmethod
    def is_heavy(piece: str):
        if piece == 'Q' or piece == 'q' or piece == 'R' or piece == 'r':
            return True
        else:
            return False

    # 是否是兵
    @staticmethod
    def is_pawn(piece: str) -> bool:
        if piece == 'P' or piece == 'p':
            return True
        else:
            return False

    # 是否是国王
    @staticmethod
    def is_king(piece: str) -> bool:
        if piece == 'K' or piece == 'k':
            return True
        else:
            return False

    # 当前行是否属于先锋区域
    @staticmethod
    def is_outpost(index: int) -> bool:
        # bug fixed 实际上的先锋是3456线 但反映到棋盘上其实是2345，因为是从0 开始的
        if 2 <= index <= 5:
            return True
        else:
            return False

    # 当前列是否属于中心区域
    @staticmethod
    def is_middle(index: int) -> bool:
        if 3 <= index <= 6:
            return True
        else:
            return False

    # 传入一个棋盘的list 解析其中的内容，方便估值函数使用 尽量时间复杂度(n^2)
    def parse_internal_board_info(self, root_board: chess.Board, fen) -> dict:
        # 自动转换 方便点
        if isinstance(root_board, list) is not True:
            board = self.parse_board(root_board)
        else:
            board = root_board
        res = {
            # 黑白棋分别进攻的格点 数字代表次数 比如2就是这个格子被人进攻了两次
            "white_attack": self.get_empty_board_list(),
            "black_attack": self.get_empty_board_list(),
            # 黑白攻击的矩阵
            "black": self.get_empty_piece_type_list(),
            "white": self.get_empty_piece_type_list(),
            # 棋盘3,4,5,6线的轻子和兵 先锋
            "white_outpost": [],
            "black_outpost": [],

            # 位置和攻击各记录一份
            "white_pieces": self.get_empty_piece_type_list(),
            "black_pieces": self.get_empty_piece_type_list(),
            'all_pawn_piled': None,
            'white_pawn_piled': None,
            'black_pawn_piled': None,
            'white_bad_castle_rook': [],
            'black_bad_castle_rook': [],
            # 黑白受到威胁的子力
            'white_threaten': [],
            'black_threaten': [],

            # 黑白通路兵
            'white_promotion_pawn': [],
            'black_promotion_pawn': [],

            # 当前颜色 evaluate.Color
            'current_color': self.get_current_color_by_fen(fen),
        }

        # 先判断叠兵吧
        all_res, white_res, black_res = self.get_pawn_piled(board)
        res['all_pawn_piled'] = all_res
        res['white_pawn_piled'] = white_res
        res['black_pawn_piled'] = black_res

        for i in range(8):
            for j in range(8):
                piece = board[i][j]
                # 非空节点才有必要处理
                if piece != evaluate.Pieces.EMPTY:
                    single_attack = self.get_single_attack(root_board, i, j)
                    # 需要额外处理一次
                    res = self.set_attacks(res, single_attack, piece, i, j)
                    res = self.set_pieces(res, piece, i, j)
                    # 处理先锋 轻子
                    if self.is_outpost(i) and (self.is_light(piece) or self.is_pawn(piece)):
                        res = self.set_outposts(res, piece, i, j, single_attack)

        # 棋子信息都处理完了 再考虑王车易位
        res = self.check_bad_castle(res, root_board)

        # 处理威胁 必须得获取所有的棋子信息
        res = self.check_threaten(res)

        # 处理通路兵
        res = self.get_promotion(res)

        return res

    # 判断通路兵
    def get_promotion(self, info: dict) -> dict:
        white_pawns = info['white_pieces']['pawn']
        black_pawns = info['black_pieces']['pawn']

        for i in range(len(white_pawns)):
            pawn = white_pawns[i]
            res = self.check_single_is_promotion(black_pawns, pawn['x'], pawn['y'], evaluate.Color.WHITE)
            if res is True:
                info['white_promotion_pawn'].append({
                    'x': pawn['x'],
                    'y': pawn['y'],
                })

        for i in range(len(black_pawns)):
            pawn = black_pawns[i]
            res = self.check_single_is_promotion(white_pawns, pawn['x'], pawn['y'], evaluate.Color.BLACK)
            if res is True:
                info['black_promotion_pawn'].append({
                    'x': pawn['x'],
                    'y': pawn['y'],
                })
        return info

    # 判断单个兵是否是通路
    # 自身 左右的格子不能有兵拦着 对白棋来说对手的兵如果y坐标比自己的大可以忽略 黑棋反之 因为已经超过自己了 不会阻挡升变
    @staticmethod
    def check_single_is_promotion(oppo_pawn: list, x, y, color: evaluate.Color) -> bool:
        # 包括自身在内的三个位置
        y1 = y - 1
        y2 = y + 1

        for i in range(len(oppo_pawn)):
            pawn = oppo_pawn[i]
            oppo_x = pawn['x']
            oppo_y = pawn['y']
            # 判断条件是白棋的路线上有黑棋 黑棋的路线有白棋
            if color == evaluate.Color.WHITE and x > oppo_x:
                if y == oppo_y or y1 == oppo_y or y2 == oppo_y:
                    # 不是通路兵
                    return False
            elif color == evaluate.Color.BLACK and x < oppo_x:
                if y == oppo_y or y1 == oppo_y or y2 == oppo_y:
                    # 不是通路兵
                    return False
            else:
                continue
        return True

    # 判断所有棋子受威胁的情况
    def check_threaten(self, info: dict) -> dict:
        info = self.check_single_threaten(info, evaluate.Color.WHITE)
        info = self.check_single_threaten(info, evaluate.Color.BLACK)
        return info

    # 获取每个棋子的信息
    @staticmethod
    def get_every_pieces_info(info: dict, color: evaluate.Color) -> tuple:
        if color == evaluate.Color.WHITE:
            text = 'white'
        else:
            text = 'black'
        bishop = info[text]['bishop']
        rook = info[text]['rook']
        queen = info[text]['queen']
        knight = info[text]['knight']
        pawn = info[text]['pawn']
        king = info[text]['king']
        return bishop, knight, rook, queen, pawn, king

    # 判断每个颜色的棋子是否受到威胁
    def check_single_threaten(self, info: dict, color: evaluate.Color) -> dict:
        if color == evaluate.Color.WHITE:
            text = 'white'
            threat_text = 'white_threaten'
            # 判断攻击是被对方攻击 而不是自己攻击对方
            attack_text = 'black_attack'
        else:
            text = 'black'
            threat_text = 'black_threaten'
            attack_text = 'white_attack'
        attacked = info[attack_text]

        # 把每个棋子的信息都获取到
        bishop, knight, rook, queen, pawn, king = self.get_every_pieces_info(info, color)
        # 挨个判断
        for i in range(len(bishop)):
            x = bishop[i]['x']
            y = bishop[i]['y']
            check = self.check_if_threatened(info, x, y, color, evaluate.Pieces.WHITE_BISHOP)
            if check is True:
                info[threat_text].append({
                    'x': x,
                    'y': y
                })
        for i in range(len(rook)):
            x = rook[i]['x']
            y = rook[i]['y']
            check = self.check_if_threatened(info, x, y, color, evaluate.Pieces.WHITE_ROOK)
            if check is True:
                info[threat_text].append({
                    'x': x,
                    'y': y
                })
        for i in range(len(queen)):
            x = queen[i]['x']
            y = queen[i]['y']
            check = self.check_if_threatened(info, x, y, color, evaluate.Pieces.WHITE_QUEEN)
            if check is True:
                info[threat_text].append({
                    'x': x,
                    'y': y
                })
        for i in range(len(knight)):
            x = knight[i]['x']
            y = knight[i]['y']
            check = self.check_if_threatened(info, x, y, color, evaluate.Pieces.WHITE_KNIGHT)
            if check is True:
                info[threat_text].append({
                    'x': x,
                    'y': y
                })
        return info

    # 判断这个棋子是否受到威胁 不能只看攻击列表 还得看子力强弱 先不判断棋子被钉死的情况
    # 计算不准确或许可以考虑用蒙特卡洛树解决
    def check_if_threatened(self, info: dict, x: int, y: int, color: evaluate.Color
                            , piece_type: evaluate.Pieces) -> bool:
        if color == evaluate.Color.WHITE:
            oppo_color = evaluate.Color.BLACK
            attack_list_text = 'white_attack'
            oppo_attack_list_text = 'black_attack'
        else:
            oppo_color = evaluate.Color.WHITE
            attack_list_text = 'black_attack'
            oppo_attack_list_text = 'white_attack'

        # 获取对方的棋子情况 同时获取自身的棋子
        bishop, knight, rook, queen, pawn, king = self.get_every_pieces_info(info, oppo_color)
        # self_bishop, self_knight, self_rook, self_queen, self_pawn,
        # self_king = self.get_every_pieces_info(info, color)

        attack_list = info[attack_list_text]
        oppo_attack_list = info[oppo_attack_list_text]

        # 被对方攻击然而自己没人保护 直接返回True节约性能
        if oppo_attack_list[x][y] > 0 and attack_list[x][y] == 0:
            return True

        # 被兵攻击就是威胁 因为兵吃任何棋子都不亏
        for i in range(len(pawn)):
            attack = pawn[i]
            if attack['attack'][x][y] != evaluate.Pieces.EMPTY:
                return True

        # 重子被轻子威胁 直接就是威胁了
        # 这里直接用白棋的枚举 全部是白棋
        if piece_type == evaluate.Pieces.WHITE_ROOK or piece_type == evaluate.Pieces.WHITE_QUEEN:
            for i in range(len(bishop)):
                attack = bishop[i]
                if attack['attack'][x][y] != evaluate.Pieces.EMPTY:
                    return True
            for i in range(len(knight)):
                attack = knight[i]
                if attack['attack'][x][y] != evaluate.Pieces.EMPTY:
                    return True
            # 后被车威胁
            if piece_type == evaluate.Pieces.WHITE_QUEEN:
                for i in range(len(rook)):
                    attack = rook[i]
                    if attack['attack'][x][y] != evaluate.Pieces.EMPTY:
                        return True

        return False

    # 将获取到的棋子放入数组
    def set_pieces(self, info: dict, piece: str, x: int, y: int) -> dict:
        if self.is_white(piece):
            color_text = 'white_pieces'
        else:
            color_text = 'black_pieces'
        piece_text = self.get_piece_type_text(piece)
        info[color_text][piece_text].append({
            'x': x,
            'y': y
        })
        return info

    # 将获取到的进攻状态进行处理
    def set_attacks(self, info: dict, attack: list, piece: str, x: int, y: int) -> dict:
        if self.is_white(piece):
            attack_type = 'white_attack'
            color = 'white'
        else:
            attack_type = "black_attack"
            color = 'black'
        piece_text = self.get_piece_type_text(piece)
        for i in range(8):
            for j in range(8):
                # 不是空的棋盘格点 才增加 不然没体现出攻击的概念
                if attack[i][j] != evaluate.Pieces.EMPTY:
                    info[attack_type][i][j] += 1
        info[color][piece_text].append({
            'x': x,
            'y': y,
            'attack': attack
        })
        return info

    # 传入缩写返回全称
    @staticmethod
    def get_piece_type_text(piece: str) -> str:
        if piece == 'p' or piece == 'P':
            return 'pawn'
        if piece == 'q' or piece == 'Q':
            return 'queen'
        if piece == 'b' or piece == 'B':
            return 'bishop'
        if piece == 'n' or piece == 'N':
            return 'knight'
        if piece == 'r' or piece == 'R':
            return 'rook'
        if piece == 'k' or piece == 'K':
            return 'king'

    # 给先锋棋子赋值
    def set_outposts(self, info: dict, piece: str, x: int, y: int, attack: list):
        if self.is_white(piece):
            outpost_type = 'white_outpost'
        else:
            outpost_type = 'black_outpost'
        info[outpost_type].append({
            'x': x,
            'y': y,
            'piece': piece
        })
        return info

    # 检查是否存在无法王车易位 挡住车路线
    def check_bad_castle(self, info, root_board: chess.Board) -> dict:
        # 分别判断王能否长短易位  True 白 False 黑
        if root_board.has_kingside_castling_rights(evaluate.Color.WHITE) is False and root_board \
                .has_queenside_castling_rights(evaluate.Color.WHITE) is False:
            info = self.if_king_between_rook(info, evaluate.Color.WHITE)

        if root_board.has_kingside_castling_rights(evaluate.Color.BLACK) is False and root_board \
                .has_queenside_castling_rights(evaluate.Color.BLACK) is False:
            info = self.if_king_between_rook(info, evaluate.Color.BLACK)
        return info

    # 判断王是否在两个车中间 如果不能王车易位还是这种情况就可能有问题
    @staticmethod
    def if_king_between_rook(info, color: evaluate.Color) -> bool:
        if color is evaluate.Color.WHITE:
            pieces = 'white_pieces'
            rook_type = 'white_bad_castle_rook'
        else:
            pieces = 'black_pieces'
            rook_type = 'black_bad_castle_rook'
        # 王不可能有两个 也不需要处理这种特殊情况
        king = info[pieces]['king'][0]
        rooks = info[pieces]['rook']
        # 车只有1个 必须判断(比如一边车被吃 另一边不能王车易位 车被卡住的糟糕情况 ,为0 被吃光了估计就是残局了 不需要判断了
        if len(rooks) == 1:
            info[rook_type].append(rooks[0])
            return info
        if len(rooks) == 0:
            return info
        # 有超过两个的车 基本就是大优局面了
        if len(rooks) > 2:
            return info
        rook1 = rooks[0]
        rook2 = rooks[1]
        # 王在两个车中间
        if (rook1['y'] < king['y'] < rook2['y']) or (rook2['y'] < king['y'] < rook1['y']):
            info[rook_type].append(rook1)
            info[rook_type].append(rook2)
            return info
        else:
            return info

    # 估值函数
    def do_evaluate(self, root_board: chess.Board, info: dict) -> float:
        result = root_board.result()
        if result != evaluate.Result.NOT_STOP:
            if result == evaluate.Result.WHITE_WIN:
                return 100
            elif result == evaluate.Result.BLACK_WIN:
                return -100
            elif result == evaluate.Result.DRAW:
                return 0
            else:
                raise "出现其他的值->" + result

        board = self.parse_board(root_board)
        game_course = self.get_current_game_course(board)
        score: list = self.get_empty_board_list()

        # 先把得分的数组赋值处理好
        for i in range(8):
            for j in range(8):
                piece = board[i][j]
                score[i][j] = evaluate.Score.SCORE_LIST[game_course][piece]
        # 计算叠兵带来的损失
        # print("子力差异 score->", self.calc_score(score))
        score = self.calc_piled_pawn(score, info, game_course)
        # print("计算完叠兵,score->", self.calc_score(score))
        score = self.calc_bad_rook(score, info, game_course)
        # print("计算完坏车,score->", self.calc_score(score))
        score = self.calc_piece_control_bonus(score, board, info, game_course)
        # print("计算每个棋子控制格点奖励 ,score->", self.calc_score(score))
        score = self.calc_threaten(score, info, game_course)
        # print("计算威胁后 score->", self.calc_score(score))
        score = self.calc_promotion(score, info, game_course)
        # print("计算通路兵后 score->", self.calc_score(score))
        score = self.calc_outpost(score, info, game_course)
        # print("计算先锋后 score->", self.calc_score(score))
        return self.calc_score(score)

    # 计算先锋棋子的加成
    def calc_outpost(self, score, info: dict, game_course: str) -> list:
        white_outpost = info['white_outpost']
        black_outpost = info['black_outpost']
        white_threaten = info['white_threaten']
        black_threaten = info['black_threaten']
        # 是先锋且不受威胁则可以加分
        for i in range(len(white_outpost)):
            single = white_outpost[i]
            x = single['x']
            y = single['y']
            piece = single['piece']
            check_threaten = self.if_in_threaten(x, y, white_threaten)
            distance = self.get_distance(x, y, evaluate.Color.WHITE)
            if check_threaten is False:
                score[x][y] += evaluate.Outpost.SET[game_course][piece][distance]

        # 是先锋且不受威胁则可以加分
        for i in range(len(black_outpost)):
            single = black_outpost[i]
            x = single['x']
            y = single['y']
            piece = single['piece']
            check_threaten = self.if_in_threaten(x, y, black_threaten)
            distance = self.get_distance(x, y, evaluate.Color.BLACK)
            if check_threaten is False:
                score[x][y] += evaluate.Outpost.SET[game_course][piece][distance]
        return score

    # 判断棋子是否受到威胁
    @staticmethod
    def if_in_threaten(x, y, threaten: list) -> bool:
        for i in range(len(threaten)):
            threaten_x = threaten[i]['x']
            threaten_y = threaten[i]['y']
            if x == threaten_x and y == threaten_y:
                return True
        return False

    # 计算整个数组的分数
    @staticmethod
    def calc_score(score: list) -> float:
        res: float = 0
        for i in range(8):
            for j in range(8):
                res += score[i][j]
        return res / 100

    # 计算叠兵的扣分问题
    def calc_piled_pawn(self, score: list, info: dict, game_course: str) -> list:
        white_piled = info['white_pawn_piled']
        black_piled = info['black_pawn_piled']
        white_attack = info['white_attack']
        black_attack = info['black_attack']
        score = self.calc_single_piled_pawn(score, white_piled, white_attack, black_attack, evaluate.Color.WHITE,
                                            game_course)
        score = self.calc_single_piled_pawn(score, black_piled, white_attack, black_attack, evaluate.Color.BLACK,
                                            game_course)
        return score

    # 对某个叠兵进行处理
    @staticmethod
    def calc_single_piled_pawn(score: list, piled: list, white_attack, black_attack, color: evaluate.Color,
                               game_course: str) -> list:
        for i in range(len(piled)):
            single = piled[i]
            x = single['x']
            y = single['y']
            # 大家都没攻击就是normal
            if white_attack[x][y] == 0 and black_attack[x][y] == 0:
                flag = 'normal'
            # 攻击和保护的次数相同 且不为0
            elif white_attack[x][y] != 0 and black_attack[x][y] != 0 and white_attack[x][y] == black_attack[x][y]:
                flag = 'attack_and_protected'
            # 对白棋来说这是保护 对黑棋来说这是攻击
            elif white_attack[x][y] > black_attack[x][y]:
                if color is True:
                    flag = 'protected'
                else:
                    flag = 'attacked'
            elif black_attack[x][y] > white_attack[x][y]:
                if color is True:
                    flag = 'attacked'
                else:
                    flag = 'protected'
            else:
                raise '出现了特殊情况'
            score[x][y] += evaluate.PawnPiled.SET[game_course][flag]
        return score

    # 计算不能王车易位的坏车
    def calc_bad_rook(self, score: list, info: dict, game_course: str) -> list:
        white_bad_castle_rook = info['white_bad_castle_rook']
        black_bad_castle_rook = info['black_bad_castle_rook']
        # 获取控制格点的文案
        score = self.calc_single_bad_rook(score, info, white_bad_castle_rook, game_course, evaluate.Color.WHITE)
        score = self.calc_single_bad_rook(score, info, black_bad_castle_rook, game_course, evaluate.Color.BLACK)
        return score

    # 对每个车单独计算 简化代码
    @staticmethod
    def calc_single_bad_rook(score: list, info: dict, rook_list, game_course: str, color: evaluate.Color) -> list:
        text = 'rook'
        for i in range(len(rook_list)):
            rook = rook_list[i]
            count = 0
            temp_rook_list = info['white'][text]
            for j in range(len(temp_rook_list)):
                single_rook_list = temp_rook_list[j]
                if rook['x'] == single_rook_list['x'] and rook['y'] == single_rook_list['y']:
                    for x in range(8):
                        for y in range(8):
                            if single_rook_list['attack'][x][y] != evaluate.Pieces.EMPTY:
                                count += 1

                # 根据车控制的格点不同 给不同的惩罚
                if count <= evaluate.BadCastleRook.threshold['narrow']:
                    place_type = 'narrow'
                elif evaluate.BadCastleRook.threshold['narrow'] < count <= evaluate.BadCastleRook.threshold['wide']:
                    place_type = 'middle'
                else:
                    place_type = 'wide'
                if color is evaluate.Color.WHITE:
                    score[rook['x']][rook['y']] += evaluate.BadCastleRook.SET[game_course][place_type]
                else:
                    score[rook['x']][rook['y']] -= evaluate.BadCastleRook.SET[game_course][place_type]
                break
        return score

    # 计算每个棋子能控制大范围的情况下 给予的奖励
    def calc_piece_control_bonus(self, score: list, board: list, info: dict, game_course: str) -> list:
        for i in range(8):
            for j in range(8):
                piece = board[i][j]
                # 王和兵不进行判断
                if piece != evaluate.Pieces.EMPTY and piece != evaluate.Pieces.BLACK_PAWN \
                        and piece != evaluate.Pieces.WHITE_PAWN \
                        and piece != evaluate.Pieces.WHITE_KING and piece != evaluate.Pieces.BLACK_KING:
                    piece_text = self.get_piece_type_text(piece)
                    if self.is_white(piece):
                        color = 'white'
                    else:
                        color = 'black'
                    piece_list = info[color][piece_text]
                    count = self.get_attack_count(piece_list, i, j)
                    # 根据棋子控制的格点不同 给不同的奖励
                    if count <= evaluate.PieceControlBonus.threshold[piece_text]['narrow']:
                        place_type = 'narrow'
                    elif evaluate.BadCastleRook.threshold['narrow'] < count <= evaluate.BadCastleRook.threshold['wide']:
                        place_type = 'middle'
                    else:
                        place_type = 'wide'
                    if self.is_white(piece):
                        score[i][j] += evaluate.PieceControlBonus.SET[game_course][piece_text][place_type]
                    else:
                        score[i][j] -= evaluate.PieceControlBonus.SET[game_course][piece_text][place_type]
        return score

    # 获取每个棋子控制的格子数
    @staticmethod
    def get_attack_count(piece_type_list: list, x: int, y: int) -> int:
        count = 0
        for i in range(len(piece_type_list)):
            single = piece_type_list[i]
            if single['x'] == x and single['y'] == y:
                attack = single['attack']
                for x in range(8):
                    for y in range(8):
                        if attack[x][y] != evaluate.Pieces.EMPTY:
                            count += 1
                # 计算过了就直接退出了
                break

        return count

    # 计算受到威胁的子力
    @staticmethod
    def calc_threaten(score: list, info: dict, game_course: str) -> list:
        # 先预留局面判断
        white_threaten = info['white_threaten']
        black_threaten = info['black_threaten']
        current_color = info['current_color']

        # 判断当前是谁在落子 如果是白棋 那白色的威胁可以忽略一部分 比如捉了一个棋子自然可以走开，黑棋的话也只能把价值最大的棋子置0
        # 因为威胁多个棋子也不可能吃掉多个
        # 如果是轮到白棋
        # 黑棋取威胁最大的 因为白棋能把黑棋最厉害的棋子吃掉
        # 白棋忽略威胁最大的 其他的都算威胁 因为只能解决最大的那个威胁
        max_black_threaten = 0
        max_black_x = 0
        max_black_y = 0
        max_white_x = 0
        max_white_y = 0
        max_white_threaten = 0

        # 先把最大值求出来
        for i in range(len(white_threaten)):
            x = white_threaten[i]['x']
            y = white_threaten[i]['y']
            # 以下是求最大值
            max_white_threaten = max_white_threaten if max_white_threaten > score[x][y] else score[x][y]
            max_white_x = max_white_x if max_white_threaten > score[x][y] else x
            max_white_y = max_white_y if max_white_threaten > score[x][y] else y

        for i in range(len(black_threaten)):
            x = black_threaten[i]['x']
            y = black_threaten[i]['y']

            # 以下是求最大值 注意黑棋是取最小值
            max_black_threaten = max_black_threaten if max_black_threaten < score[x][y] else score[x][y]
            max_black_x = max_black_x if max_black_threaten > score[x][y] else x
            max_black_y = max_black_y if max_black_threaten > score[x][y] else y

        # 判断颜色
        if current_color is evaluate.Color.WHITE:
            for i in range(len(white_threaten)):
                x = white_threaten[i]['x']
                y = white_threaten[i]['y']
                if x == max_white_x and y == max_white_y:
                    continue
                else:
                    score[x][y] = 0

            for i in range(len(black_threaten)):
                x = black_threaten[i]['x']
                y = black_threaten[i]['y']
                if x != max_black_x and y != max_black_y:
                    continue
                else:
                    score[x][y] = 0
        else:
            for i in range(len(white_threaten)):
                x = white_threaten[i]['x']
                y = white_threaten[i]['y']
                if x != max_white_x and y != max_white_y:
                    continue
                else:
                    score[x][y] = 0

            for i in range(len(black_threaten)):
                x = black_threaten[i]['x']
                y = black_threaten[i]['y']
                if x == max_black_x and y == max_black_y:
                    continue
                else:
                    score[x][y] = 0

        return score

    # 计算通路兵
    def calc_promotion(self, score: list, info: dict, game_course: str) -> list:
        white_promotion_pawn = info['white_promotion_pawn']
        black_promotion_pawn = info['black_promotion_pawn']

        # 挨个计算
        for i in range(len(white_promotion_pawn)):
            pawn = white_promotion_pawn[i]
            x = pawn['x']
            y = pawn['y']
            score = self.calc_single_promotion(score, x, y, info, evaluate.Color.WHITE, game_course)
        for i in range(len(black_promotion_pawn)):
            pawn = black_promotion_pawn[i]
            x = pawn['x']
            y = pawn['y']
            score = self.calc_single_promotion(score, x, y, info, evaluate.Color.BLACK, game_course)
        return score

    # 获取进攻和防守的数组
    @staticmethod
    def get_protected_and_attacked(info: dict, color: evaluate.Color) -> tuple:
        if color == evaluate.Color.WHITE:
            protect = info['white_attack']
            attack = info['black_attack']
        else:
            protect = info['black_attack']
            attack = info['white_attack']
        return protect, attack

    # 获取棋子到底线的距离
    @staticmethod
    def get_distance(x, y, color: evaluate.Color) -> int:
        if color == evaluate.Color.WHITE:
            return x
        else:
            return 7 - x

    # 计算单个通路兵
    def calc_single_promotion(self, score, x, y, info, color: evaluate.Color, game_course: str) -> list:
        protect, attack = self.get_protected_and_attacked(info, color)

        distance = self.get_distance(x, y, color)
        temp_score = evaluate.PawnWillPromotion.SET[game_course][distance]
        if attack[x][y] > protect[x][y]:
            temp_score = temp_score * evaluate.PawnWillPromotion.WEAK_LOSS
        if color is evaluate.Color.WHITE:
            score[x][y] += temp_score
        else:
            score[x][y] -= temp_score
        return score

    # 检查棋盘状态 其实是检查为什么不能继续下棋了
    # 直接返回字符串 吐给前端了
    @staticmethod
    def check_board_status(board: chess.Board):
        if board.is_checkmate() is True:
            return {'end': True, 'result': '将杀'}
        if board.can_claim_threefold_repetition():
            return {'end': True, 'result': '三次重复局面和棋'}
        if board.can_claim_fifty_moves():
            return {'end': True, 'result': '50步不吃子或者不动兵和棋'}
        if board.is_insufficient_material():
            return {'end': True, 'result': '缺少必要的棋子和棋'}
        if not any(board.generate_legal_moves()):
            return {'end': True, 'result': '无子可动和棋'}
        return {'end': False, 'result': '无'}

    # 当棋局结束时获取value
    @staticmethod
    def get_end_value(status: str) -> float:
        if status == evaluate.Result.WHITE_WIN:
            return 100
        elif status == evaluate.Result.BLACK_WIN:
            return -100
        elif status == evaluate.Result.DRAW:
            return 0
